# -*- coding: utf-8 -*-
import time, socket, random, threading

def recv_all_from(s, end = '\r\n\r\n'):
    data = ''
    while 1:
        data += s.recv(1024)
        if not data or data.find(end) != -1:
            break
    return data

class serResHandle:
    httpcode = {200: 'HTTP/1.1 200 OK\r\n',
            201: 'HTTP/1.1 201 Created\r\n',
            202: 'HTTP/1.1 202 Accepted\r\n',
            203: 'HTTP/1.1 203 Non-Authoritative Information\r\n',
            204: 'HTTP/1.1 204 No Content\r\n',
            205: 'HTTP/1.1 205 Reset Content\r\n',
            206: 'HTTP/1.1 206 Partial Content\r\n',
            300: 'HTTP/1.1 300 Multiple Choices\r\n',
            301: 'HTTP/1.1 301 Moved Permanently\r\n',
            302: 'HTTP/1.1 302 Moved Temporarily\r\n',
            303: 'HTTP/1.1 303 See Other\r\n',
            304: 'HTTP/1.1 304 Not Modified\r\n',
            305: 'HTTP/1.1 305 Use Proxy\r\n',
            307: 'HTTP/1.1 307 Temporary Redirect\r\n',
            400: 'HTTP/1.1 400 HTTP/1.1 400 Bad Request\r\n',
            401: 'HTTP/1.1 401 Unauthorized\r\n',
            402: 'HTTP/1.1 402 Payment Required\r\n',
            403: 'HTTP/1.1 403 Forbidden\r\n',
            404: 'HTTP/1.1 404 Not Found\r\nContent-Type: text/html; charset=UTF-8\r\n',
            405: 'HTTP/1.1 405 Method Not Allowed\r\n',
            406: 'HTTP/1.1 406 Not Acceptable\r\n',
            407: 'HTTP/1.1 407 Proxy Authentication Required\r\n',
            408: 'HTTP/1.1 408 Request Timeout\r\n',
            414: 'HTTP/1.1 414 Request-URI Too Long\r\n',
            417: 'HTTP/1.1 417 Expectation Failed\r\n',
            503: 'HTTP/1.1 503 Service Unavailable\r\n',
            504: 'HTTP/1.1 505 Gateway Timeout\r\n'
            }
    resBasePage = {200:'<html><body bgcolor="green"><h2>%s</h2></body></html>',
                   404:'<html><body bgcolor="red"><h2>404 page not Found</h2></body></html>',
                   302:'<html><body bgcolor="blue"><h2>Page after Location</h2></body></html>'}
    def __init__(self):
        self.listenPort = 8000
        self.latency = 0
        self.resCode = 200
        self.keepAliveTime = 60
        self.httpHeaders = {}
        self.pageSize = 0
        self.pageFile = ''
        self.page = ''
        self.host = ''
        self.request = ''
        self.ifStart = True
        self.ifPrint = False
        self.ifStop = False
        self.serverThread = []
    def create_res_header(self):
        httpHeaderStr = ''
        for i in self.httpHeaders.keys():
            httpHeaderStr += '%s: %s\r\n'%(i, self.httpHeaders[i])
        return httpHeaderStr    
    def get_page_as_code(self, serAddr):
        if self.resCode == 200:
            self.httpHeaders['Content-Length'] = self.pageSize
            httpHeaderStr = self.create_res_header()
            if not self.pageFile:
                if self.pageSize <= len(self.resBasePage[200]%serAddr): 
                    self.page = self.httpcode[200] + httpHeaderStr + '\r\n' + self.resBasePage[200]%serAddr 
                else:
                    self.page = self.httpcode[200] + httpHeaderStr + '\r\n' + self.resBasePage[200]%serAddr + (self.pageSize - len(self.resBasePage[200]%serAddr))*'#'            
            else:
                self.page = self.httpcode[200] + httpHeaderStr + '\r\n' + self.pageFile     
        elif self.resCode == 404:
            self.httpHeaders['Content-Length'] = len(self.resBasePage[404])
            httpHeaderStr = self.create_res_header()
            self.page = self.httpcode[404] + httpHeaderStr + '\r\n' + self.resBasePage[404]
        elif self.resCode == 301 or self.resCode == 302:
            httpHeaderStr = self.create_res_header()
            httpHeaderStr += 'Location: http://%s/location.htm\r\n'%self.host
            self.page = self.httpcode[self.resCode] + httpHeaderStr + '\r\n'
        else:
            self.page = self.httpcode[self.resCode] + '\r\n'
    def res_page_as_request(self, serAddr):
        start = time.time()
        if self.request.find('ms.html')!=-1:
            num = float(self.request[1:self.request.find('ms.html')])/1000
            time.sleep(num)
        elif self.request.find('random.html')!=-1:
            num = random.uniform(1, 3)
            time.sleep(num)
        elif self.request.find('location.htm')!=-1:
            self.page = self.httpcode[200] + 'Content-Length: %d\r\n\r\n'%len(self.resBasePage[302]) + self.resBasePage[302]
            return self.page
        else:
            time.sleep(self.latency)
        self.get_page_as_code(serAddr)
    def sock_mesg_handle(self, sock):
        if sock.getsockname()[0].find(':')==-1:
            serAddr = '%s:%s'%(sock.getsockname()[0], sock.getsockname()[1])
            self.httpHeaders['Client-IP'] = '%s:%s'%(sock.getpeername()[0], sock.getpeername()[1])    
        else:
            serAddr = '[%s]:%s'%(sock.getsockname()[0], sock.getsockname()[1])
            self.httpHeaders['Client-IP'] = '[%s]:%s'%(sock.getpeername()[0], sock.getpeername()[1])    
        self.httpHeaders['Server-IP'] = serAddr
        self.host = serAddr    
        if self.keepAliveTime:
            sock.settimeout(self.keepAliveTime)
            self.httpHeaders['Connection'] = 'keep-alive'
            while not self.ifStop:
                try:
                    recvdata = recv_all_from(sock)
                except:
                    #self.if_print('can not recv data!')
                    return
                if not recvdata:
                    sock.close()
                    return
                self.if_print(recvdata.split('\r\n\r\n')[0])
                mesg = recvdata.split('\r\n')
                mesg1 = mesg[0].split(' ')
                if len(mesg1) >= 2: 
                    self.request = mesg1[1]
                else:
                    self.request = '/index.html'
                self.res_page_as_request(serAddr)
                for i in mesg:
                    if i.lower().find('connection: close') != -1:
                        sock.send(self.page)
                        sock.close()
                        return
                try:
                    sock.send(self.page)
                except:
                    return
        elif self.keepAliveTime == 0:
            self.httpHeaders['Connection'] = 'Close'
            try:
                recvdata = recv_all_from(sock)
            except:
                #self.if_print('can not recv data!')
                return
            if not recvdata:
                sock.close()
                return
            self.if_print(recvdata.split('\r\n\r\n')[0])
            mesg = recvdata.split('\r\n')
            mesg1 = mesg[0].split(' ')
            if len(mesg1) >= 2: 
                self.request = mesg1[1]
            else:
                self.request = '/index.html'           
            self.res_page_as_request()
            try:
                sock.send(self.page)
            except:
                return
            sock.close()                    
    def start_server(self):   
        ss=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        ss.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        Saddr = ('0.0.0.0', self.listenPort)
        ss.bind(Saddr)
        ss.listen(5)
        print 'server %s:%s is started!'%Saddr
        testnum = 0
        while not self.ifStop:
            try:
                sc, addr = ss.accept()
            except:
                if self.ifStop:
                    print 'server %s:%s is stopped!'%Saddr
                return
            testnum += 1
            self.if_print('%s [TEST-%d START] %s'%('#'*24, testnum, '#'*24))
            self.if_print("[test-%d] %s is connected!"%(testnum, addr ))
            threading.Thread(target = self.sock_mesg_handle, args = (sc, )).start()
    def start_server6(self):
        ss=socket.socket(socket.AF_INET6,socket.SOCK_STREAM)
        ss.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        Saddr = ('::', self.listenPort)
        ss.bind(Saddr)
        ss.listen(5)
        print 'server %s:%s is started!'%Saddr
        testnum = 0
        while not self.ifStop:
            try:
                sc, addr = ss.accept()
            except:
                if self.ifStop:
                    print 'server %s:%s is stopped!'%Saddr
                return
            testnum += 1
            self.if_print('%s [TEST-%d START] %s'%('#'*24, testnum, '#'*24))
            self.if_print("[I am test-%d] %s is connected!"%(testnum, addr ))
            threading.Thread(target = self.sock_mesg_handle, args = (sc, )).start()       
    def if_print(self, s):
        if self.ifPrint:
            print s
    def run(self):
        self.ifStart = True
        self.ifStop = False
        self.serverThread.append(threading.Thread(target = self.start_server))
        self.serverThread.append(threading.Thread(target = self.start_server6))
        for t in self.serverThread:
            t.setDaemon(1)
            t.start()
    def stop(self):
        self.ifStop = True
        self.serverThread = []
    def help(self):
        print '''
read me!
1) when you get /1ms.html, server will respond after 1ms
   when you get /500ms.html, server will respond after 500ms
2) when you get /random.html, server will respond after random second(1-3S)
4) when you get other, server will respond immediately
'''
    

if __name__ == '__main__': 
    pass

         